﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Dynamic;
using System.Linq;
using System.Web;
using PostSharp.Aspects;
using PostSharp.Aspects.Advices;
using PostSharp.Aspects.Configuration;
using PostSharp.Aspects.Internals;
using PostSharp.Extensibility;
using SignalR.Hubs;

namespace Mvc3SignalR.Aspects
{
    /// <summary>
    /// Aspect that, when apply on a class, fully implements the interface 
    /// <see cref="INotifyPropertyChanged"/> into that class, and overrides all properties to
    /// that they raise the event <see cref="INotifyPropertyChanged.PropertyChanged"/>.
    /// </summary>
    [Serializable]
    public sealed class KnockoutAspect : LocationInterceptionAspect
    {
        //public override void OnGetValue(LocationInterceptionArgs args)
        //{
        //    base.OnGetValue(args);
        //    //IClientAgent agent = ((IHub) args.Instance).Agent;
        //    //if(agent != null)
        //    //{
        //    //    agent.Invoke(args.Location.Name);
        //    //}
        //    if (args.Instance.IsTracking())
        //    {
        //        args.Instance.TrackObservable(args.Location.Name);
        //    }
        //}

        /// <summary>
        /// Method invoked <i>instead</i> of the <c>Set</c> semantic of the field or property to which the current aspect is applied,
        ///             i.e. when the value of this field or property is changed.
        /// </summary>
        /// <param name="args">Advice arguments.</param>
        public override void OnSetValue(LocationInterceptionArgs args)
        {
            base.OnSetValue(args);
            var agent = ((IHub)args.Instance).Agent;
            if (agent != null)
            {
                agent.Invoke(args.Location.Name, args.GetCurrentValue());
            }

        }
    }
    ///// <summary>
    ///// Aspect that, when apply on a class, fully implements the interface 
    ///// <see cref="INotifyPropertyChanged"/> into that class, and overrides all properties to
    ///// that they raise the event <see cref="INotifyPropertyChanged.PropertyChanged"/>.
    ///// </summary>
    //[Serializable]
    //public sealed class KnockoutComputedAspect : LocationInterceptionAspect
    //{
    //    /// <summary>
    //    /// Method invoked <i>instead</i> of the <c>Set</c> semantic of the field or property to which the current aspect is applied,
    //    ///             i.e. when the value of this field or property is changed.
    //    /// </summary>
    //    /// <param name="args">Advice arguments.</param>
    //    public override void OnGetValue(LocationInterceptionArgs args)
    //    {
    //        //args.Instance.StartTracking();
    //        base.OnGetValue(args);
    //        //args.Instance.StopTracking();
    //        ((IHub)args.Instance).Agent.Invoke(args.Location.Name, args.GetCurrentValue());
    //    }
    //}

    //internal static class DependencyTracking
    //{
    //    private static readonly Dictionary<object, List<string>> isTracking = new Dictionary<object, List<string>>();
    //    private static readonly Dictionary<string, string> dependants = new Dictionary<string, string>();


    //    public static void StartTracking(this object context)
    //    {
    //        isTracking[context] = new List<string>();
    //    }

    //    public static void StopTracking(this object context)
    //    {
    //        isTracking[context] = null;
    //    }

    //    public static void ShouldNotify(this object context, string propertyName)
    //    {

    //        isTracking[context] = null;
    //    }

    //    public static bool IsTracking(this object context)
    //    {
    //        List<string> result;
    //        return isTracking.TryGetValue(context, out result) && result != null;
    //    }

    //    public static bool HasDependants(this object context, string propertyName)
    //    {
    //        List<string> result;
    //        return dependants[context].
    //        return isTracking.TryGetValue(context, out result) && result != null;
    //    }
    //    public static bool IsTracking(this object context, string propertyName)
    //    {
    //        List<string> properties = isTracking[context];
    //        return context.IsTracking() && properties.Contains(propertyName);
    //    }

    //    public static void TrackObservable(this object context, string propertyName)
    //    {
    //        Debug.Assert(context.IsTracking(), "Must be tracking object in order to call this method");
    //        List<string> properties = isTracking[context];
    //        if(!properties.Contains(propertyName))
    //        {
    //            properties.Add(propertyName);
    //        }
    //    }
    //}

    //internal class Dependency
    //{
    //    public object Context { get; set; }
    //    public string ChangingProperty { get; set; }
    //    public string ShouldNotifyProperty { get; set; }
    //}
}